#include "camera.h"

using namespace std;

Camera::Camera() : Object()
{
    frameCt = 0;
    frames = NULL;
}

Camera::Camera( Scene* scn, Trajectory* traj, Orientation* ornt, const Vector& u, int filmW, int filmH, double fovy ) :
Object(traj,ornt)
{

    frameCt = 0;
    frames = NULL;

    _scn = scn;
    _u = u;
    _filmW = filmW;
    _filmH = filmH;
    _fovy = fovy * PI / 180;

    _ZImg = _filmH / ( 2 * tan( _fovy / 2 ) );
}

Camera::~Camera()
{
    delete [] frames;
}

Ray Camera::spawnRay( double i, double j, double t )
{
    _z = -d( t );
    _x = _u.crossProduct( _z ).u();
    _y = _z.crossProduct( _x ).u();
    double x = j - _filmW / 2,
           y = _filmH / 2 - i,
           z = -_ZImg;
    Vector dWorld = Vector( _x * x + _y * y + _z * z );
    return Ray( this->p(t), dWorld, 0, _scn->nRefr(), t );
}

void Camera::initFrames( double t0, double t1, int fps )
{
    ASSERT( t1 > t0 );
    if( frameCt > 0 )
        delete [] frames;
    double dt = 1.0 / fps;
    frameCt = (int)( ( t1 - t0 ) / dt );
    frames = new Frame[frameCt];
    for( int i=0; i<frameCt; i++ )
        frames[i].init( _filmW, _filmH, t0 + dt * i );
}

void Camera::render( Frame& f )
{
    int w = f.w();
    int h = f.h();
    double t = f.t();

    #pragma mta assert parallel
    #pragma mta block schedule
    for( int ij=0; ij<w*h; ij++ )
    {
        int i = ij / w;
        int j = ij % h;
        Ray r = spawnRay( i, j, t );
        Color c = _scn->trace( r );
        f.setPixel( i, j, c );
    }
}

void Camera::videoRender()
{
    int w = frames[0].w();
    int h = frames[0].h();

    #pragma mta assert parallel
    #pragma mta block schedule
    for( int kij = 0; kij < frameCt * h * w; kij ++ )
    {
       int k   = kij / (w * h);
       int Tij = kij % (w * h);
       int i   = Tij / w;
       int j   = Tij % w;

       Ray r = spawnRay( i, j, frames[k].t() );
       Color c = _scn->trace( r );
       frames[k].setPixel( i, j, c );
    }
}

void Camera::writeFrames( const string& baseName, const string& extension )
{
    #pragma mta serial
    for( int i=0; i<frameCt; i++ )
        frames[i].save( baseName + num2str( frames[i].t(), 4, 0 ) + extension );
}
